#include "snake.hpp"

/* Snake Class Deffinition */

Snake::Snake(Game &my_game) : locGame(my_game) {
  history.push_back(my_game.getField().size() / 2);
}

template <typename _comp, typename _lambda>
void Snake::define_direction(_comp comp, _lambda head) {
  auto head_cord = history.front();
  auto newPos = head(head_cord);

  if (!getBigger) {
    history.pop_back();
  } else {
    getBigger = !getBigger;
  }

  if (comp(newPos) and
      std::find(history.begin(), history.end(), newPos) == history.end()) {
    history.push_front(newPos);
  } else {
    locGame.gameover();
  }
}

void Snake::cycle() {
  if (length > history.size()) {
    getBigger = true;
  }
  switch (this->direction) {
  case 1: {
    auto newPos = [](unsigned int head) { return head - 1; };
    auto comp = [this](unsigned int newPos) {
      return newPos >= 0 and
             newPos % (locGame.Size().first) != (locGame.Size().first - 1);
    };
    define_direction(comp, newPos);
    break;
  }
  case 2: {
    auto newPos = [this](unsigned int head) {
      return head - locGame.Size().first;
    };
    auto comp = [](unsigned int newPos) { return (newPos >= 0); };
    define_direction(comp, newPos);
    break;
  }
  case 3: {
    auto newPos = [](unsigned int head) { return (head + 1); };
    auto comp = [this](unsigned int newPos) {
      return (newPos <= locGame.getField().size() and
              newPos % (locGame.Size().first) != 0);
    };
    define_direction(comp, newPos);
    break;
  }
  case 4: {
    auto newPos = [this](unsigned int head) {
      return (head + locGame.Size().first);
    };
    auto comp = [this](unsigned int newPos) {
      return (newPos <= locGame.getField().size());
    };
    define_direction(comp, newPos);
    break;
  }
  case 0:
  default:
    break;
  }
  if (history.front() == locGame.get_food_cord()) {
    ++length;
    locGame.new_food(length * history.front());
  }
}
